package com.wy._02io.fileUtil;


import com.wy.Exception.FileNotExistException;
import com.wy._02io.enums.FileRelationEnum;
import com.wy._02io.enums.FileDirEnum;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 关于文件关系的工具类。
 */
public class FileRelation {

    /**
     * 得到所有存在文件的绝对路径
     *
     * @param fileDir 本地文件路径
     * @return 所有小文件的集合
     */
    public static List<String> getAllFilePaths(String fileDir) {
        List<String> strings = new ArrayList<>();
        getAllFilePaths(judgmentPath(fileDir), strings);
        return strings;
    }

    /**
     * 因为是递归，所以写的很小心尽量都不要和其他代码合起来
     *
     * @param path  传入本地磁盘的路径。
     * @param paths 用来接收文件路径的集合
     */
    private static void getAllFilePaths(File path, List<String> paths) {
        for (File file : Objects.requireNonNull(path.listFiles())) {
            if (file.isDirectory()) {
                getAllFilePaths(file, paths);
                continue;
            }
            paths.add(file.toString());
        }
    }

    /**
     * 校验文件是否存在
     *
     * @param fileDir 目录文件
     * @return 文件存在的话返回文件
     */
    private static File judgmentPath(String fileDir) {
        File dir = new File(fileDir);
        if (!dir.exists()) {
            throw new FileNotExistException();
        }
        return dir;
    }

    /**
     * 得到当前目录下的所有儿子目录
     * 比如：A下面有B C D  B下面有D E。。只会返回 BCD
     *
     * @param file
     */
    public static List<File> getCurrentDirAllSonDir(File file) {
        List<File> fileList = new ArrayList<>();
        if (file != null) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isDirectory()) {
                    fileList.add(file1);
                }
            }
        }
        return fileList;
    }

    /**
     * 得到当前目录下的所有儿子文件，如果A下面有B目录，C文件，D文件，只会返回C he D文件
     *
     * @param file
     * @return
     */
    public static List<File> getCurrentDirAllSonFile(File file) {
        List<File> fileList = new ArrayList<>();
        if (file != null) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isFile()) {
                    fileList.add(file1);
                }
            }
        }
        return fileList;
    }

    /**
     * 删除此目录下的所有儿子级别的文件
     *
     * @param file
     */
    public static void deleteCurrentDirAllSonFile(File file) {
        if (file != null && file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isFile()) {
                    file1.delete();
                }
            }
        }
    }

    /**
     * API演示
     */
    public static void apiDemo() {
        File file = new File("E:\\uploadFile\\新建文件夹\\c9331e2715bb46989737fa971dfbc6d5\\111.jpg");
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getName());
        System.out.println(file.getAbsoluteFile().toString());
        System.out.println(file.getAbsoluteFile().getName());
        System.out.println(file.getParent());
        System.out.println(file.getParentFile().getName());
        System.out.println(file.getParentFile().getPath());
    }

    /**
     * 得到此目录下所有有效的目录
     * <p>
     * 有效的目录 指的是这个目录下有文件，或者说这个目录下面什么都没有。就算有效的目录。
     *
     * @param directoryPath
     * @return
     */
    public static List<String> getAllAvailableDirs(String directoryPath) {
        List<String> availablePaths = new ArrayList<>();
        getAllAvailableDirs(directoryPath, availablePaths);
        return availablePaths;
    }

    /**
     * 得到所有有效的目录，有效指的是当前目录下 全部文件， 什么都没有  或者既有文件也有目录。
     *
     * @param directoryPath 目标目录
     * @param availablePaths 有效的结果集合，因为是一个递归
     * @return 返回所有的 有效结果
     */
    private static List<String> getAllAvailableDirs(String directoryPath, List<String> availablePaths) {
        File directory = new File(directoryPath);
        // 检查目录是否存在
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                int fileCount = 0;
                for (File file : files) {
                    if (file.isDirectory()) {
                        int dirStatus = getFileStatus(file.getAbsolutePath());
                        if (dirStatus == 0) {
                            availablePaths.add(file.getAbsolutePath());
                        }
                        if (dirStatus == 1) {
                            availablePaths.add(file.getAbsolutePath());
                        }
                        if (dirStatus == 2) {
                            getAllAvailableDirs(file.getAbsolutePath(), availablePaths);
                        }
                        if (dirStatus == 3) {
                            getAllAvailableDirs(file.getAbsolutePath(), availablePaths);
                        }
                    } else if (file.isFile()) {
                        if (fileCount == 0) {
                            availablePaths.add(file.getParentFile().getAbsolutePath());
                            fileCount++;
                        }
                    }
                }
            }
        }
        return availablePaths;
    }

    /**
     * 得到目录的状态，4种
     *
     * @return
     */
    private static int getFileStatus(String path) {
        int dirCount = 0;
        int fileCount = 0;
        File file = new File(path);
        File[] files = file.listFiles();
        if (files == null) {
            System.out.println("咋能为空呢");
        }
        for (File file1 : files) {
            if (file1.isDirectory()) {
                dirCount++;
            }
            if (file1.isFile()) {
                fileCount++;
            }
        }
        //稍微繁琐，
        if (dirCount == 0 && fileCount == 0) {
            return 0;
        }
        if (dirCount == 0 && fileCount != 0) {
            return 1;
        }
        if (dirCount != 0 && fileCount == 0) {
            return 2;
        }
        if (dirCount != 0 && fileCount != 0) {
            return 3;
        }
        return 0;

    }

    /**
     * 得到文件层级数量。 基本就是根据斜杠计算的。
     * <p>
     * window下是这样的
     *
     * @return
     */
    public static int getFileHierarchyCount(File file) {
        if (file == null || !file.exists()) {
            throw new RuntimeException("文件异常");
        }
        String absolutePath = file.getAbsolutePath();
        int count = 0;
        for (int i = 0; i < absolutePath.length(); i++) {
            if (absolutePath.charAt(i) == '\\') {
                count++;
            }
        }
        count++;
        return count;
    }

    /**
     * 判断两个文件的关系  firstFile 是  secondFile 的什么
     *
     * @param firstFile  第一个文件
     * @param secondFile 第二个文件
     * @return 返回文件可能的关系  A第一个文件叫第二个文件什么
     */
    public static FileRelationEnum getFileRelation(File firstFile, File secondFile) throws IOException {
        //判断是否存在为空
        if ((firstFile == null) ||
                (secondFile == null) ||
                (!firstFile.exists()) ||
                (!secondFile.exists())) {
            return null;
        }
        int abs = Math.abs(getFileHierarchyCount(firstFile) - getFileHierarchyCount(secondFile));
        //        根据目录数量判断可能的关系
        List<FileRelationEnum> fileProbablyRelateByDirCount1 = FileRelationEnum.getFileProbablyRelateByDirCount(abs);
        //        判断具体的关系是什么  校验具体的关系
        return checkoutOneRelation(abs, fileProbablyRelateByDirCount1, firstFile, secondFile);
    }

    /**
     * 检查目录差距是1的时候 文件的关系
     * <p>
     * 护着 说换一种思路。别说差多少 就传入一个可能的集合，然后逐个判断 或者写一个方法，传入一个枚举，两个文件，判断这两个文件是否是这种关系
     *
     * @param distance
     * @param fileRelationEnumList
     * @param firstFile
     * @param secondFile
     * @return
     * @throws IOException
     */
    private static FileRelationEnum checkoutOneRelation(int distance, List<FileRelationEnum> fileRelationEnumList, File firstFile, File secondFile) throws IOException {
        if (!getRootFile(firstFile).getPath().equals(getRootFile(secondFile).getPath())) {
            return FileRelationEnum.NONE;
        }
        if (distance == 0) {
            if (firstFile.toString().equals(secondFile.toString())) {
                return FileRelationEnum.ONESELF;
            }
            FileDirEnum firstTypeType = getFileType(firstFile);
            FileDirEnum secondFileType = getFileType(secondFile);
            File firstFileParentFile = firstFile.getParentFile();
            File secondFileParentFile = secondFile.getParentFile();
            if (equalsFile(firstFileParentFile, secondFileParentFile)
                    && firstTypeType == FileDirEnum.FILE
                    && firstTypeType == secondFileType) {
                return FileRelationEnum.SISTER;
            }
            if (equalsFile(firstFileParentFile, secondFileParentFile)
                    && firstTypeType == FileDirEnum.Directory
                    && firstTypeType == secondFileType) {
                return FileRelationEnum.BROTHER;
            }
            if (!equalsFile(firstFileParentFile, secondFileParentFile)
                    && firstTypeType != secondFileType) {
                return FileRelationEnum.BROTHER;
            }
            if (getRootFile(firstFile).getPath().equals(getRootFile(secondFile).getPath())
                    && !equalsFile(firstFileParentFile, secondFileParentFile)) {
                return FileRelationEnum.BESIDE_PITFH;
            }
            System.out.println(0 + "错误");
        }
        if (distance == 1) {
            if (equalsFile(secondFile.getParentFile(), firstFile)
                    && getFileType(firstFile) == FileDirEnum.Directory) {
                return FileRelationEnum.SON;
            }
            if (equalsFile(secondFile.getParentFile(), firstFile)
                    && getFileType(firstFile) == FileDirEnum.FILE) {
                return FileRelationEnum.DAUGHTER;
            }
            if (equalsFile(firstFile.getParentFile(), secondFile)) {
                return FileRelationEnum.FATHER;
            }
            if (getFileHierarchyCount(firstFile) > getFileHierarchyCount(secondFile)
                    && getFileType(secondFile) == FileDirEnum.FILE
                    && !checkIsRootDir(firstFile)
                    && !checkIsRootDir(firstFile.getParentFile())
                    && equalsFile(firstFile.getParentFile().getParentFile(), secondFile)) {
                return FileRelationEnum.AUNT;
            }
            if (getFileHierarchyCount(firstFile) > getFileHierarchyCount(secondFile)
                    && getFileType(secondFile) == FileDirEnum.Directory
                    && !checkIsRootDir(secondFile)
                    && equalsFile(firstFile.getParentFile().getParentFile(), secondFile.getParentFile())) {
                return FileRelationEnum.UNCLE;
            }
            System.out.println(1 + "错误");
        }
        if (distance == 2) {
            if (getFileHierarchyCount(firstFile) > getFileHierarchyCount(secondFile)
                    && getFileType(secondFile) == FileDirEnum.Directory
                    && equalsFile(firstFile.getParentFile().getParentFile(), secondFile)) {
                return FileRelationEnum.GRANDFATHER;
            }
            if (getFileHierarchyCount(firstFile) < getFileHierarchyCount(secondFile)
                    && getFileType(firstFile) == FileDirEnum.Directory
                    && getFileType(secondFile) == FileDirEnum.Directory
                    && equalsFile(secondFile.getParentFile().getParentFile(), firstFile)) {
                return FileRelationEnum.GRANDSON;
            }
            if (getFileHierarchyCount(firstFile) < getFileHierarchyCount(secondFile)
                    && getFileType(firstFile) == FileDirEnum.Directory
                    && getFileType(secondFile) == FileDirEnum.FILE
                    && equalsFile(secondFile.getParentFile().getParentFile(), firstFile.getParentFile())) {
                return FileRelationEnum.GRANDDAUGHTER;
            }
            if (getFileHierarchyCount(firstFile) > getFileHierarchyCount(secondFile)
                    && getFileType(secondFile) == FileDirEnum.FILE
                    && equalsFile(firstFile.getParentFile().getParentFile().getParentFile(), secondFile.getParentFile())) {
                return FileRelationEnum.FATHER_AUNT;
            }
            if (getFileHierarchyCount(firstFile) > getFileHierarchyCount(secondFile)
                    && !checkIsRootDir(secondFile)
                    && getFileType(secondFile) == FileDirEnum.Directory
                    && equalsFile(firstFile.getParentFile().getParentFile().getParentFile(), secondFile.getParentFile())) {
                return FileRelationEnum.FATHER_UNCLE;
            }
            System.out.println(2 + "错误");
        }
        if (distance >= 3) {
            if (getFileHierarchyCount(firstFile) < getFileHierarchyCount(secondFile)) {
                return FileRelationEnum.FOREFATHERS;
            }
//            TODO: 这儿还是有很多问题的，一个是没有全部包这些关系，另一个是没有做完全的测试。
            return FileRelationEnum.YOUNG_PITFH;
        }
        return null;
    }

    /**
     * 得到根目录文件
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static File getRootFile(File file) throws IOException {
        if (!CheckFile.checkFile(file)) {
            throw new RuntimeException("文件异常");
        }
        File canonicalFile = file.getCanonicalFile();
        return new File(canonicalFile.getPath().split("\\\\")[0]).getCanonicalFile();
    }

    /**
     * 得到文件类型
     *
     * @param file
     * @return
     */
    public static FileDirEnum getFileType(File file) {
        if (!CheckFile.checkFile(file)) {
            throw new RuntimeException("文件异常");
        }
//        file
        if (file.isDirectory()) {
            return FileDirEnum.Directory;
        }
        if (file.isFile()) {
            return FileDirEnum.FILE;
        }
        return FileDirEnum.OTHER;
    }

    /**
     * 检查是否为根目录
     *
     * @param file
     * @return
     */
    public static boolean checkIsRootDir(File file) {
        if (!CheckFile.checkFile(file)) {
            throw new RuntimeException("文件异常");
        }
        return getFileType(file) == FileDirEnum.Directory && (file.getParentFile() == null || getFileHierarchyCount(file) == 1);
    }

    /**
     * 比较两个文件是否相等
     * 从 目录数量 文件类型 文件名字比较
     *
     * @param file1
     * @param file2
     * @return
     */
    public static boolean equalsFile(File file1, File file2) {
        if (!CheckFile.checkFile(file1) || !CheckFile.checkFile(file2)) {
            throw new RuntimeException("文件异常");
        }
        FileDirEnum fileType1 = getFileType(file1);
        FileDirEnum fileType2 = getFileType(file2);
        if (fileType1 == FileDirEnum.OTHER || fileType2 == FileDirEnum.OTHER) {
            throw new RuntimeException("文件类型异常");
        }
        if (getFileHierarchyCount(file1) != getFileHierarchyCount(file2)
                || fileType1 != fileType2
                || !file1.getPath().equals(file2.getPath())) {
            return false;

        }
        return true;
    }
}
